package cn.wokoba.service.trade.service.setlement;

import cn.wokoba.service.trade.adapter.port.ITradePort;
import cn.wokoba.service.trade.adapter.repository.ITradeRepository;
import cn.wokoba.service.trade.model.aggregate.GroupBuyTeamSettlementAggregate;
import cn.wokoba.service.trade.model.entity.*;
import cn.wokoba.service.trade.service.ITradeSettlementOrderService;
import cn.wokoba.service.trade.service.setlement.factory.TradeSettlementRuleFilterFactory;
import cn.wokoba.types.enums.NotifyTaskHTTPEnumVO;
import com.alibaba.fastjson.JSON;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
@Slf4j
public class TradeSettlementOrderService implements ITradeSettlementOrderService {
    @Resource
    private ITradeRepository repository;
    @Resource
    private TradeSettlementRuleFilterFactory settlementRuleFilterFactory;
    @Resource
    ITradePort port;

    @Override
    public TradePaySettlementEntity settlementMarketPayOrder(TradePaySuccessEntity tradePaySuccessEntity) throws Exception {
        log.info("拼团交易-支付订单结算:{} outTradeNo:{}", tradePaySuccessEntity.getUserId(), tradePaySuccessEntity.getOutTradeNo());
        // 1. 结算规则过滤
        TradeSettlementRuleFilterBackEntity tradeSettlementRuleFilterBackEntity = settlementRuleFilterFactory.openLogicLink(tradePaySuccessEntity.getSource(),
                tradePaySuccessEntity.getChannel(),
                tradePaySuccessEntity.getUserId(),
                tradePaySuccessEntity.getOutTradeNo(),
                tradePaySuccessEntity.getOutTradeTime());

        String teamId = tradeSettlementRuleFilterBackEntity.getTeamId();

        // 2. 查询组团信息
        GroupBuyTeamEntity groupBuyTeamEntity = GroupBuyTeamEntity.builder()
                .teamId(tradeSettlementRuleFilterBackEntity.getTeamId())
                .activityId(tradeSettlementRuleFilterBackEntity.getActivityId())
                .targetCount(tradeSettlementRuleFilterBackEntity.getTargetCount())
                .completeCount(tradeSettlementRuleFilterBackEntity.getCompleteCount())
                .lockCount(tradeSettlementRuleFilterBackEntity.getLockCount())
                .status(tradeSettlementRuleFilterBackEntity.getStatus())
                .validStartTime(tradeSettlementRuleFilterBackEntity.getValidStartTime())
                .validEndTime(tradeSettlementRuleFilterBackEntity.getValidEndTime())
                .notifyUrl(tradeSettlementRuleFilterBackEntity.getNotifyUrl())
                .build();

        // 3. 构建聚合对象
        GroupBuyTeamSettlementAggregate groupBuyTeamSettlementAggregate = GroupBuyTeamSettlementAggregate.builder()
                .userEntity(UserEntity.builder().userId(tradePaySuccessEntity.getUserId()).build())
                .groupBuyTeamEntity(groupBuyTeamEntity)
                .tradePaySuccessEntity(tradePaySuccessEntity)
                .build();

        // 4. 拼团交易结算
        boolean isNotify = repository.settlementMarketPayOrder(groupBuyTeamSettlementAggregate);

        // 5. 组队回调处理 - 处理失败也会有定时任务补偿
        if (isNotify) {
            Map<String, Integer> notifyResultMap = execSettlementNotifyJob(teamId);
            log.info("回调通知拼团完结 result:{}", JSON.toJSONString(notifyResultMap));
        }
        // 6. 返回结算信息
        return TradePaySettlementEntity.builder()
                .source(tradePaySuccessEntity.getSource())
                .channel(tradePaySuccessEntity.getChannel())
                .userId(tradePaySuccessEntity.getUserId())
                .teamId(teamId)
                .activityId(groupBuyTeamEntity.getActivityId())
                .outTradeNo(tradePaySuccessEntity.getOutTradeNo())
                .build();
    }


    public Map<String, Integer> processFailedSettlementRefund() {
        //查询需要退款的orderList
        Map<String, List<GroupBuyRefundEntity>> groupBuyRefundEntityMap = repository.queryGroupBuyRefundEntity();
        int successCount = 0, errorCount = 0;
        //调用远程服务处理退款
        for (String teamId : groupBuyRefundEntityMap.keySet()) {
            List<GroupBuyRefundEntity> groupBuyRefundEntityList = groupBuyRefundEntityMap.get(teamId);
            for (GroupBuyRefundEntity groupBuyRefundEntity : groupBuyRefundEntityList) {
                String orderId = groupBuyRefundEntity.getOrderId();
                String userId = groupBuyRefundEntity.getUserId();
                String response = port.refundNotify(groupBuyRefundEntity);
                if (NotifyTaskHTTPEnumVO.SUCCESS.getCode().equals(response)) {
                    repository.updateOrderListStatus2Refund(orderId, userId);
                    successCount += 1;
                } else {
                    log.error("拼团超时自动退款失败 userId:{},orderId:{}", userId, orderId);
                    //告警人工处理
                    errorCount += 1;
                }
            }
            repository.updateOrderStatus2Fail(teamId);
        }
        //结果返回
        return Map.of("successCount", successCount, "errorCount", errorCount);
    }


    @Override
    public Map<String, Integer> execSettlementNotifyJob() throws Exception {
        log.info("拼团交易-执行结算通知任务");
        // 查询未执行任务
        List<NotifyTaskEntity> notifyTaskEntityList = repository.queryUnExecutedNotifyTaskList();
        return execSettlementNotifyJob(notifyTaskEntityList);
    }

    private Map<String, Integer> execSettlementNotifyJob(String teamId) throws Exception {
        log.info("拼团交易-执行结算通知回调，指定 teamId:{}", teamId);
        List<NotifyTaskEntity> notifyTaskEntityList = repository.queryUnExecutedNotifyTaskList(teamId);
        return execSettlementNotifyJob(notifyTaskEntityList);
    }

    private Map<String, Integer> execSettlementNotifyJob(List<NotifyTaskEntity> notifyTaskEntityList) throws Exception {
        int successCount = 0, errorCount = 0, retryCount = 0;
        for (NotifyTaskEntity notifyTask : notifyTaskEntityList) {
            String response = port.groupBuyNotify(notifyTask);
            if (NotifyTaskHTTPEnumVO.SUCCESS.getCode().equals(response)) {
                int updateCount = repository.updateNotifyTaskStatusSuccess(notifyTask.getTeamId());
                if (1 == updateCount) {
                    successCount += 1;
                }
            } else if (NotifyTaskHTTPEnumVO.ERROR.getCode().equals(response)) {
                if (notifyTask.getNotifyCount() >= 5) {
                    int updateCount = repository.updateNotifyTaskStatusError(notifyTask.getTeamId());
                    if (1 == updateCount) {
                        errorCount += 1;
                    }
                } else {
                    int updateCount = repository.updateNotifyTaskStatusRetry(notifyTask.getTeamId());
                    if (1 == updateCount) {
                        retryCount += 1;
                    }
                }
            }
        }
        Map<String, Integer> resultMap = new HashMap<>();
        resultMap.put("waitCount", notifyTaskEntityList.size());
        resultMap.put("successCount", successCount);
        resultMap.put("errorCount", errorCount);
        resultMap.put("retryCount", retryCount);
        return resultMap;
    }
}

